#include <assert.h>
#include <stdio.h>
#include <Judy.h>

#include "../normalization/normalized_datatypes.h"
#include "../normalization/globals.h"
#include "../normalization/utils.h"

Pvoid_t normalized_atomic_concepts_left;

/*
void add_subsumer(NormalizedAtomicConcept* ac, NormalizedConcept* c) {
	int judy_return;
	switch (c->type) {
		case NORMALIZED_ATOMIC_CONCEPT:
			J1S(judy_return, ac->subsumers, (Word_t) c);
			if (judy_return == JERR) {
				fprintf(stderr, "could not add subsumer\n");
				exit(-1);
			}
			break;
		case NORMALIZED_EXISTENTIAL_RESTRICTION:
			J1S(judy_return, c->description.exists->subsumees, (Word_t) ac);
			if (judy_return == JERR) {
				fprintf(stderr, "could not add subsumee\n");
				exit(-1);
			}
			break;
		default:
			fprintf(stderr, "add_subsumer: no other normalized concept type possible here, aborting!\n");
			exit(-1);
	}
}
*/

/*
void add_subsumer(NormalizedAtomicConcept* ac, NormalizedConcept* c) {
	int judy_return;
	int judy_return1;
	Word_t index;

	switch (c->type) {
		case NORMALIZED_ATOMIC_CONCEPT:
			index = 0;
			J1F(judy_return, c->description.atomic->subsumers, index);
			while (judy_return == 1) {
				J1S(judy_return1, ac->subsumers, index);
				J1N(judy_return, c->description.atomic->subsumers, index);
			}

			J1S(judy_return, ac->subsumers, (Word_t) c);
			if (judy_return == JERR) {
				fprintf(stderr, "could not add subsumer\n");
				exit(-1);
			}
//
// 			J1S(judy_return, c->description.atomic->subsumees, (Word_t) ac);
// 
// 			index = 0;
// 			J1F(judy_return, ac->subsumees, index);
// 			while (judy_return == 1) {
// 				J1S(judy_return1, ((NormalizedAtomicConcept*) index)->subsumers, (Word_t) c);
// 				J1N(judy_return, ac->subsumees, index);
// 			}
// 
// 
			break;
		case NORMALIZED_EXISTENTIAL_RESTRICTION:
			J1S(judy_return, c->description.exists->subsumees, (Word_t) ac);
			if (judy_return == JERR) {
				fprintf(stderr, "could not add subsumee\n");
				exit(-1);
			}
			break;
		default:
			fprintf(stderr, "add_subsumer: no other normalized concept type possible here, aborting!\n");
			exit(-1);
	}
}
*/

int is_subsumer_of(NormalizedAtomicConcept* ac, NormalizedConcept* c) {
	int is_subsumer;
	switch (c->type) {
		case NORMALIZED_ATOMIC_CONCEPT:
			J1T(is_subsumer, ac->subsumers, (Word_t) c);
			break;
		case NORMALIZED_EXISTENTIAL_RESTRICTION:
			J1T(is_subsumer, c->description.exists->subsumees, (Word_t) ac);
			break;
		default:
			fprintf(stderr, "no other normalized concept type possible here, aborting!\n");
			exit(-1);
	}
	return is_subsumer;
}


/*
void push_to_concepts_to_process(NormalizedAtomicConcept* c, NormalizedConcept* d) {

	NormalizedConcept** tmp;
	
	tmp = realloc(c->concepts_to_process, (c->number_of_concepts_to_process + 1) * sizeof(NormalizedConcept*));
	assert(tmp != NULL);
	c->concepts_to_process = tmp;
	c->concepts_to_process[c->number_of_concepts_to_process] = d;
	++c->number_of_concepts_to_process;

	// int judy_return;
	// J1S(judy_return, c->concepts_to_process, (Word_t) d);
	// if (judy_return == JERR) {
	// 	fprintf(stderr, "could not push to concepts to process, aborting!\n");
	// 	exit(-1);
	// }
}
*/


/*
NormalizedConcept* pop_from_concepts_to_process(NormalizedAtomicConcept* c) {

	NormalizedConcept* ret; 
	NormalizedConcept** tmp;

	if (c->number_of_concepts_to_process == 0) {
		fprintf(stderr, "no concepts to process, aborting!\n");
		exit(-1);
	}
	ret = c->concepts_to_process[c->number_of_concepts_to_process - 1];
	tmp = realloc(c->concepts_to_process, (c->number_of_concepts_to_process - 1) * sizeof(NormalizedConcept*));
	assert(tmp != NULL);
	c->concepts_to_process = tmp;
	--(c->number_of_concepts_to_process);
	return ret;

	// int judy_return;
	// Word_t index = 0;

	// J1F(judy_return, c->concepts_to_process, index);
	// if (judy_return == 0) {
	// 	fprintf(stderr, "could not pop from concepts to process, aborting!\n");
	// 	exit(-1);
	// }
	// J1U(judy_return, c->concepts_to_process, index);
	// return (NormalizedConcept*) index;
}
*/

void push_to_stacks_to_process(NormalizedAtomicConcept* c, Pvoid_t s) {
	/*
	NormalizedAtomicConcept** tmp;
        
	tmp = realloc(s->stack, (s->size + 1) * sizeof(NormalizedAtomicConcept*));
        assert(tmp != NULL);
	s->stack = tmp;
        s->stack[s->size] = c;
        ++(s->size);
	*/
	int judy_return;

	J1S(judy_return, s, (Word_t) c);
	if (judy_return == JERR) {
		fprintf(stderr, "could not push to stack, aborting!\n");
		exit(-1);
	}
}

NormalizedAtomicConcept* pop_from_stacks_to_process(Pvoid_t s) {
	/*
	NormalizedAtomicConcept* ret; 
	NormalizedAtomicConcept** tmp;

	// if (s.count <= 0) {
	if (stack_empty(s)) {
		fprintf(stderr, "concept stack empty!\n");
		exit(-1);
	}
	ret = s->stack[s->size - 1];
	tmp = realloc(s->stack, (s->size - 1) * sizeof(NormalizedAtomicConcept*));
        assert(tmp != NULL);
	s->stack = tmp;
        --(s->size);
	return ret;
	*/
	int judy_return;
	Word_t index;

	J1F(judy_return, s, index);
	if (judy_return == 0) {
		fprintf(stderr, "could not pop from stack, aborting!\n");
		exit(-1);
	}
	J1U(judy_return, s, index);
	return (NormalizedAtomicConcept*) index;
}

/*
void push_rhs_to_concepts_to_process(NormalizedAtomicConcept* ac, NormalizedSubClassAxiom* ax) {
	int judy_return;
	Word_t index;

	switch (ax->rhs->type) {
		case NORMALIZED_ATOMIC_CONCEPT:
			// J1T(appears_on_lhs, normalized_atomic_concepts_left, (Word_t) ax->rhs);
			// if (!is_subsumer_of(ac, ax->rhs) && appears_on_lhs)
			if (!is_subsumer_of(ac, ax->rhs))
				push_to_concepts_to_process(ac, ax->rhs);
			break;
		case NORMALIZED_EXISTENTIAL_RESTRICTION:
			if (!is_subsumer_of(ac, ax->rhs))
				push_to_concepts_to_process(ac, ax->rhs);
			break;
		case NORMALIZED_CONJUNCTION:
			index = 0;
			J1F(judy_return, ax->rhs->description.conj->conjuncts, index);
			if (judy_return == 0) {
				fprintf(stderr,"no conjunct in conjunction, aborting\n");
				exit(-1);
			}
			while (judy_return == 1) {
				// if (!is_subsumer_of(ac, (NormalizedConcept*) index))
				// 	push_to_concepts_to_process(ac, (NormalizedConcept*) index);
				// J1N(judy_return, ax->rhs->description.conj->conjuncts, index);
				switch (((NormalizedConcept*) index)->type) {
					case NORMALIZED_ATOMIC_CONCEPT:
						// J1T(appears_on_lhs, normalized_atomic_concepts_left, index);
						// if (!is_subsumer_of(ac, (NormalizedConcept*) index) && appears_on_lhs)
						if (!is_subsumer_of(ac, (NormalizedConcept*) index))
							push_to_concepts_to_process(ac, (NormalizedConcept*) index);
						break;
					case NORMALIZED_EXISTENTIAL_RESTRICTION:
						if (!is_subsumer_of(ac, (NormalizedConcept*) index))
							push_to_concepts_to_process(ac, (NormalizedConcept*) index);
						break;
				}
				J1N(judy_return, ax->rhs->description.conj->conjuncts, index);
			}
			break;
		default:
			fprintf(stderr, "unknown normalized concept type, aborting!\n");
			exit(-1);
	}
}
*/

/*
void add_rhs_to_subsumers(NormalizedAtomicConcept* ac, NormalizedSubClassAxiom* ax) {
	int judy_return;
	Word_t index;

	switch (ax->rhs->type) {
		case NORMALIZED_ATOMIC_CONCEPT:
		case NORMALIZED_EXISTENTIAL_RESTRICTION:
			add_subsumer(ac,ax->rhs);
			break;
		case NORMALIZED_CONJUNCTION:
			index = 0;
			J1F(judy_return, ax->rhs->description.conj->conjuncts, index);
			if (judy_return == 0) {
				fprintf(stderr,"no conjunct in conjunction, aborting\n");
				exit(-1);
			}
			while (judy_return == 1) {
				add_subsumer(ac, (NormalizedConcept*) index);
				J1N(judy_return, ax->rhs->description.conj->conjuncts, index);
			}
			break;
		default:
			fprintf(stderr, "unknown normalized concept type, aborting!\n");
			exit(-1);
	}
}
*/

int subsumes(NormalizedAtomicConcept* ac, NormalizedConcept* c) {
	int subsumes, judy_return;
	Word_t index = 0L;

/*
	int judy_return1, judy_return2;
	Word_t index1 = 0L;
	Word_t index2 = 0L;
	JError_t* PJError = NULL;
*/

	switch (c->type) {
		case NORMALIZED_ATOMIC_CONCEPT:
			J1T(subsumes, ac->subsumers, (Word_t) c);
			return subsumes;
		case NORMALIZED_EXISTENTIAL_RESTRICTION:
			J1T(subsumes, c->description.exists->subsumees, (Word_t) ac);
			return subsumes;
		/*
		case NORMALIZED_ATOMIC_CONCEPT:
		case NORMALIZED_EXISTENTIAL_RESTRICTION:
			J1T(fulfills_premise, ac->subsumers, (Word_t) c);
			return fulfills_premise;
		*/
		case NORMALIZED_CONJUNCTION:

			index = 0;
			J1F(judy_return, c->description.conj->conjuncts, index);
			if (judy_return == 0) {
				fprintf(stderr,"no conjunct in conjunction, aborting\n");
				exit(-1);
			}
			while (judy_return == 1) {
				switch (((NormalizedConcept*) index)->type) {
					case NORMALIZED_ATOMIC_CONCEPT:
						J1T(subsumes, ac->subsumers, (Word_t) ((NormalizedConcept*) index));
						if (!subsumes)
							return 0;
						break;
					case NORMALIZED_EXISTENTIAL_RESTRICTION:
						J1T(subsumes, ((NormalizedConcept*) index)->description.exists->subsumees, (Word_t) ac);
						if (!subsumes)
							return 0;
						break;
					default:
						fprintf(stderr, "no other normalized concept type possible here, aborting!\n");
						exit(-1);
				}
				J1N(judy_return, c->description.conj->conjuncts, index);
			}
			return 1;

/*
			judy_return1 = Judy1First(c->description.conj->conjuncts, &index1, PJError);
			judy_return2 = Judy1First(ac->subsumers, &index2, PJError);
			while (judy_return1 && judy_return2) {
				if (index1 < index2)
					return 0;
				else if (index1 > index2) {
					index2 = index1;
					judy_return2 = Judy1First(ac->subsumers, &index2, PJError);
				}
				else {
					judy_return1 = Judy1Next(c->description.conj->conjuncts, &index1, PJError);
					judy_return2 = Judy1Next(ac->subsumers, &index2, PJError);
				}
			}
			return !judy_return1;
*/
			break;
		default:
			fprintf(stderr, "unknown normalized concept type, aborting\n");
			exit(-1);
	}
	// this is just to supress warning
	return 0;
}


